package com.hq;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 1、开启一个 ServerSocketChannel
 * 2、开启一个选择器
 * 3、ServerSocketChannel 绑定服务的Ip和G端口
 * 4、把ServerSocketChannel 注册到Selector选择上面 关注的事件为 accept 连接事件
 * 5、循环等待事件 这里可以使用select阻塞等待事件  阻塞指定时间select(timeout)  不阻塞selectNow()
 * 6、如果有事件发生 根据不同的事件处理不同的逻辑  如果是连接事件创建一个新的socket并注册到selector 设置事件为read
 * 7、处理完事件后要删除该事件，避免重复处理相同的事件
 */
public class NioService {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        Selector selector = Selector.open();

        serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1",6666));
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("注册成功的channel数量："+selector.keys().size()+"事件数量："+selector.selectedKeys().size());
        SocketChannel accept = serverSocketChannel.accept();
        //等待客户端连接
        while (true){
            if (selector.select(1000) == 0) {
                System.out.println("等待服务器连接 1秒");
                continue;
            }
            //有事件发送 处理对应的事件
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                //如果是连接时间 就给当前客户端创建一个channel 并将其注册到选择器 关注的事件为read 分配缓存大小
                if(key.isAcceptable()){
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("连接成功一个：hash值是："+socketChannel.hashCode());
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector,SelectionKey.OP_READ,ByteBuffer.allocate(1024));
                    System.out.println("注册成功的channel数量："+selector.keys().size()+"事件数量："+selector.selectedKeys().size());
                }
                //如果是一个读的事件  就消费消息
                if(key.isReadable()){
                    //根据selectionKey获取SocketChannel
                    SocketChannel channel = (SocketChannel) key.channel();
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    channel.read(buffer);
                    System.out.println("收到消息："+new String(buffer.array()));
                }
                //删除这个key  避免重复消费
                iterator.remove();
            }
        }

    }
}
